package com.yyfax.ph.common.widgets.circleindicator;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.RoundRectShape;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
import com.yyfax.ph.R;
import com.yyfax.ph.common.widgets.circleindicator.holder.ShapeHolder;

import java.util.ArrayList;
import java.util.List;

public class CircleIndicator extends View {
	private static final String TAG = CircleIndicator.class.getSimpleName();

	private ViewPager viewPager;
	private List<ShapeHolder> tabItems;
	private ShapeHolder movingItem;

	// config list
	private int mCurItemPosition;
	private float mIndicatorRadius;
	private float mIndicatorMargin;
	private int mIndicatorBackground;
	private int mIndicatorSelectedBackground;
	private Gravity mIndicatorLayoutGravity;
	private Mode mIndicatorMode;

	// default value
	private static final int DEFAULT_INDICATOR_RADIUS = 10;
	private static final int DEFAULT_INDICATOR_MARGIN = 40;
	private static final int DEFAULT_INDICATOR_BACKGROUND = Color.BLUE;
	private static final int DEFAULT_INDICATOR_SELECTED_BACKGROUND = Color.RED;
	private static final int DEFAULT_INDICATOR_LAYOUT_GRAVITY = Gravity.CENTER.ordinal();
	private static final int DEFAULT_INDICATOR_MODE = Mode.SOLO.ordinal();

	public enum Gravity {
		LEFT, CENTER, RIGHT
	}

	public enum Mode {
		INSIDE, OUTSIDE, SOLO
	}


	private int mSize;

	public CircleIndicator(Context context) {
		super(context);
		init(context, null);
	}

	public CircleIndicator(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	public CircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init(context, attrs);
	}

	private void init(Context context, AttributeSet attrs) {
		tabItems = new ArrayList<>();
		handleTypedArray(context, attrs);
	}

	private void handleTypedArray(Context context, AttributeSet attrs) {
		if (attrs == null)
			return;
		TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleIndicator);
		mIndicatorRadius = typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_radius, DEFAULT_INDICATOR_RADIUS);
		mIndicatorMargin = typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_margin, DEFAULT_INDICATOR_MARGIN);
		mIndicatorBackground = typedArray.getColor(R.styleable.CircleIndicator_ci_background, DEFAULT_INDICATOR_BACKGROUND);
		mIndicatorSelectedBackground = typedArray.getColor(R.styleable.CircleIndicator_ci_selected_background, DEFAULT_INDICATOR_SELECTED_BACKGROUND);
		int gravity = typedArray.getInt(R.styleable.CircleIndicator_ci_gravity, DEFAULT_INDICATOR_LAYOUT_GRAVITY);
		mIndicatorLayoutGravity = Gravity.values()[gravity];
		int mode = typedArray.getInt(R.styleable.CircleIndicator_ci_mode, DEFAULT_INDICATOR_MODE);
		mIndicatorMode = Mode.values()[mode];
		typedArray.recycle();
	}

	public void setViewPager(final ViewPager viewPager) {
		this.viewPager = viewPager;
		if (null != tabItems && tabItems.size() > 0) {
			tabItems.clear();
			this.invalidate();
			this.requestLayout();
		}
		mSize = this.viewPager.getAdapter().getCount();
		createTabItems();
		createMovingItem();
		setUpListener();
	}

	public void setViewPager(final ViewPager viewPager, int size) {
		this.viewPager = viewPager;
		if (null != tabItems && tabItems.size() > 0) {
			tabItems.clear();
			this.invalidate();
			this.requestLayout();
		}
		mSize = size;
		createTabItems();
		createMovingItem();
		setUpListener();
		trigger(0);
	}



	private void setUpListener() {
		viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {

			@Override
			public void onPageSelected(int position) {
				super.onPageSelected(position);
				int idx = position % mSize;
				trigger(idx);
			}
		});
	}

	private void trigger(int position) {
		mCurItemPosition = position;
		requestLayout();
		invalidate();
	}

	private void createTabItems() {
		for (int i = 0; i < mSize; i++) {
			OvalShape circle = new OvalShape();
			ShapeDrawable drawable = new ShapeDrawable(circle);
			ShapeHolder shapeHolder = new ShapeHolder(drawable);
			Paint paint = drawable.getPaint();
			paint.setColor(mIndicatorBackground);
			paint.setAntiAlias(true);
			shapeHolder.setPaint(paint);
			tabItems.add(shapeHolder);
		}
	}

	private void createMovingItem() {
//		OvalShape circle = new OvalShape();

		// 外部矩形弧度
		float[] outerR = new float[] { mIndicatorRadius, mIndicatorRadius, mIndicatorRadius, mIndicatorRadius, mIndicatorRadius, mIndicatorRadius, mIndicatorRadius, mIndicatorRadius };
		RoundRectShape roundRectShape = new RoundRectShape(outerR, null, null);

		ShapeDrawable drawable = new ShapeDrawable(roundRectShape);
		movingItem = new ShapeHolder(drawable);
		Paint paint = drawable.getPaint();
		paint.setColor(mIndicatorSelectedBackground);
		paint.setAntiAlias(true);
		switch (mIndicatorMode) {
			case INSIDE:
				paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
				break;
			case OUTSIDE:
				paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
				break;
			case SOLO:
				paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
				break;
		}
		movingItem.setPaint(paint);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		final int width = getWidth();
		final int height = getHeight();
		layoutTabItems(width, height);
		layoutMovingItem(mCurItemPosition, 0);
	}

	private void layoutTabItems(final int containerWidth, final int containerHeight) {
		if (tabItems == null) {
			return;
		}
		final float yCoordinate = containerHeight * 0.5f;
		final float startPosition = startDrawPosition(containerWidth);
		for (int i = 0; i < tabItems.size(); i++) {
			ShapeHolder item = tabItems.get(i);
			item.resizeShape(2 * mIndicatorRadius, 2 * mIndicatorRadius);
			item.setY(yCoordinate - mIndicatorRadius);
			float x = startPosition + (mIndicatorMargin + mIndicatorRadius * 2) * i;
			item.setX(x);
		}
	}

	private float startDrawPosition(final int containerWidth) {
		if (mIndicatorLayoutGravity == Gravity.LEFT)
			return 0;
		float tabItemsLength = tabItems.size() * (2 * mIndicatorRadius + mIndicatorMargin) - mIndicatorMargin;
		if (containerWidth < tabItemsLength) {
			return 0;
		}
		if (mIndicatorLayoutGravity == Gravity.CENTER) {
			return (containerWidth - tabItemsLength) / 2;
		}
		return containerWidth - tabItemsLength;
	}

	private void layoutMovingItem(final int position, final float positionOffset) {
		if (movingItem == null) {
			return;
			// throw new IllegalStateException("forget to create movingItem?");
		}
		try {
			ShapeHolder item = tabItems.get(position);
			movingItem.resizeShape(item.getWidth() + mIndicatorMargin, item.getHeight());
			float x = item.getX() + (mIndicatorMargin + mIndicatorRadius * 2) * positionOffset - mIndicatorMargin / 2;
			movingItem.setX(x);
			movingItem.setY(item.getY());
		} catch (Exception e) {
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		int sc = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
				Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
						| Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
						| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
						| Canvas.CLIP_TO_LAYER_SAVE_FLAG);
		for (ShapeHolder item : tabItems) {
			canvas.save();
			canvas.translate(item.getX(), item.getY());
			item.getShape().draw(canvas);
			canvas.restore();
		}

		if (movingItem != null) {
			canvas.save();
			canvas.translate(movingItem.getX(), movingItem.getY());
			movingItem.getShape().draw(canvas);
			canvas.restore();
		}
		canvas.restoreToCount(sc);
	}

	public void setIndicatorRadius(float mIndicatorRadius) {
		this.mIndicatorRadius = mIndicatorRadius;
	}

	public void setIndicatorMargin(float mIndicatorMargin) {
		this.mIndicatorMargin = mIndicatorMargin;
	}

	public void setIndicatorBackground(int mIndicatorBackground) {
		this.mIndicatorBackground = mIndicatorBackground;
	}

	public void setIndicatorSelectedBackground(int mIndicatorSelectedBackground) {
		this.mIndicatorSelectedBackground = mIndicatorSelectedBackground;
	}

	public void setIndicatorLayoutGravity(Gravity mIndicatorLayoutGravity) {
		this.mIndicatorLayoutGravity = mIndicatorLayoutGravity;
	}

	public void setIndicatorMode(Mode mIndicatorMode) {
		this.mIndicatorMode = mIndicatorMode;
	}
}
